package Graph.graphWithNoweight.euler;

import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.TreeSet;

/**
 * @Author: 蔡翔
 * @Date: 2020/2/3 12:43
 * @Version 1.0
 *
 * 等同于 AdjSet
 * 1
 */

public class Graph implements Cloneable {
    //节点数
    private int V;
    //边数
    private int E;
    //用红黑树 的 表示 节点的邻接关系。。
    private TreeSet<Integer>[] adj;


    public Graph(String filename){

        //从文件中读出  图的基本信息。
        File file = new File(filename);

        try(Scanner scanner = new Scanner(file)){

            V = scanner.nextInt();
            if(V < 0) {
                throw new IllegalArgumentException("V must be non-negative");
            }
            //首先 先申请整个数组的 的内存空间。 申请V 个 LinkedList 空间 为后续的数组LinkedList做准备。
            adj = new TreeSet[V];
            for(int i = 0; i < V; i ++) {
                adj[i] = new TreeSet<>();
            }

            E = scanner.nextInt();
            if(E < 0) {
                throw new IllegalArgumentException("E must be non-negative");
            }

            for(int i = 0; i < E; i ++){
                int a = scanner.nextInt();
                validateVertex(a);
                int b = scanner.nextInt();
                validateVertex(b);

                if(a == b) {
                    throw new IllegalArgumentException("Self Loop is Detected!");
                }
                if(adj[a].contains(b)) {
                    throw new IllegalArgumentException("Parallel Edges are Detected!");
                }

                adj[a].add(b);
                adj[b].add(a);
            }
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }

    public void validateVertex(int v){
        if(v < 0 || v >= V) {
            throw new IllegalArgumentException("vertex " + v + "is invalid");
        }
    }

    @Override
    protected Object clone() {
        //默认的clone 是浅拷贝，我们需要深拷贝。 深拷贝其实就是把现在这个Graph 整个对象的详细细节（比如图的具体构造 邻接边什么的）也拷贝进去
        try {
            Graph clone = (Graph)super.clone();
            //做Graph 的深拷贝           -----开始
            clone.adj = new TreeSet[V];
            for(int v=0;v<V;v++){
                clone.adj[v] = new TreeSet<>();
                for(int w:adj[v]){
                    clone.adj[v].add(w);
                }
            }
            //做Graph 的深拷贝           -----结束
            return clone;
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        //如果有异常直接返回 null
        return null;
    }

    public int V(){
        return V;
    }

    public int E(){
        return E;
    }

    public boolean hasEdge(int v, int w){
        validateVertex(v);
        validateVertex(w);
        return adj[v].contains(w);
    }

    // 无论是ArrayList 还是LinkedList 都实现了Iterable接口。 只要拿到返回值 去遍历就行了。
    public Iterable<Integer> adj(int v){
        validateVertex(v);
        return adj[v];
    }

    public int degree(int v){
        return adj[v].size();
    }

    public void removeEdge(int v,int w){
        validateVertex(v);
        validateVertex(w);
        //因为是一个无向图，所以两边都要删除
        adj[v].remove(w);
        adj[w].remove(v);
    }

    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();

        sb.append(String.format("V = %d, E = %d\n", V, E));
        for(int v = 0; v < V; v ++){
            sb.append(String.format("%d : ", v));
            for(int w : adj[v]) {
                sb.append(String.format("%d ", w));
            }
            sb.append('\n');
        }
        return sb.toString();
    }

    public static void main(String[] args){

        Graph adjSet = new Graph("g.txt");
        System.out.print(adjSet);
    }


}
